home *** CD-ROM | disk | FTP | other *** search
/ Practical Algorithms for Image Analysis / Practical Algorithms for Image Analysis.iso / TARFILE.GZ / tarfile / libtiff / tools / fax2ps.c next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  12.6 KB  |  434 lines

  1. /* $Header: /usr/people/sam/tiff/tools/RCS/fax2ps.c,v 1.10 1996/04/29 21:58:49 sam Rel $" */
  2.  
  3. /*
  4.  * Copyright (c) 1991-1996 Sam Leffler
  5.  * Copyright (c) 1991-1996 Silicon Graphics, Inc.
  6.  *
  7.  * Permission to use, copy, modify, distribute, and sell this software and 
  8.  * its documentation for any purpose is hereby granted without fee, provided
  9.  * that (i) the above copyright notices and this permission notice appear in
  10.  * all copies of the software and related documentation, and (ii) the names of
  11.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  12.  * publicity relating to the software without the specific, prior written
  13.  * permission of Sam Leffler and Silicon Graphics.
  14.  * 
  15.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  16.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  17.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  18.  * 
  19.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  20.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  21.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  22.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  23.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  24.  * OF THIS SOFTWARE.
  25.  */
  26. #include <math.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <time.h>
  31. #ifndef VMS
  32. #include <unistd.h>
  33. #else
  34. #include <unixio.h>
  35. #endif
  36.  
  37. #include "tiffio.h"
  38.  
  39. float    defxres = 204.;        /* default x resolution (pixels/inch) */
  40. float    defyres = 98.;        /* default y resolution (lines/inch) */
  41. const float basePageWidth = 8.5;
  42. const float basePageHeight = 11.0;
  43. const float half = 0.5;
  44. const float points = 72.0;
  45. float    pageWidth = 8.5;    /* image page width (inches) */
  46. float    pageHeight = 11.0;    /* image page length (inches) */
  47. int    scaleToPage = 0;    /* if true, scale raster to page dimensions */
  48. int    totalPages = 0;        /* total # pages printed */
  49. int    row;            /* current output row */
  50. int    maxline = 512;        /* max output line of PostScript */
  51.  
  52. /*
  53.  * Turn a bit-mapped scanline into the appropriate sequence
  54.  * of PostScript characters to be rendered.
  55.  *  
  56.  * Original version written by Bret D. Whissel,
  57.  * Florida State University Meteorology Department
  58.  * March 13-15, 1995.
  59.  */
  60. static void
  61. printruns(unsigned char* buf, uint16* runs, uint16* erun, uint32 lastx)
  62. {
  63.     static struct {
  64.     char white, black;
  65.     short width;
  66.     } WBarr[] = {
  67.     { 'd', 'n', 512 }, { 'e', 'o', 256 }, { 'f', 'p', 128 },
  68.     { 'g', 'q',  64 }, { 'h', 'r',  32 }, { 'i', 's',  16 },
  69.     { 'j', 't',   8 }, { 'k', 'u',   4 }, { 'l', 'v',   2 },
  70.     { 'm', 'w',   1 }
  71.     };
  72.     static char* svalue =
  73.     " !\"#$&'*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abc";
  74.     int colormode = 1;        /* 0 for white, 1 for black */
  75.     int runlength = 0;
  76.     int n = maxline;
  77.     int x = 0;
  78.     int l;
  79.  
  80.     (void) buf;
  81.     printf("%d m(", row++);
  82.     while (runs < erun) {
  83.     if (!runlength) {
  84.         colormode ^= 1;
  85.         runlength = *runs++;
  86.         if (x+runlength > lastx)
  87.         runlength = runs[-1] = lastx-x;
  88.         x += runlength;
  89.         if (!colormode && runs == erun)    
  90.         break;        /* don't bother printing the final white run */
  91.     }
  92.     /*
  93.      * If a runlength is greater than 6 pixels, then spit out
  94.      * black or white characters until the runlength drops to
  95.      * 6 or less.  Once a runlength is <= 6, then combine black
  96.      * and white runlengths until a 6-pixel pattern is obtained.
  97.      * Then write out the special character.  Six-pixel patterns
  98.      * were selected since 64 patterns is the largest power of
  99.      * two less than the 92 "easily printable" PostScript
  100.      * characters (i.e., no escape codes or octal chars).
  101.      */
  102.     l = 0;
  103.     while (runlength > 6) {    /* Run is greater than six... */
  104.         if (runlength >= WBarr[l].width) {
  105.         if (n == 0) {
  106.             putchar('\n');
  107.             n = maxline;
  108.         }
  109.         putchar(colormode ? WBarr[l].black : WBarr[l].white), n--;
  110.         runlength -= WBarr[l].width;
  111.         } else
  112.         l++;
  113.     }
  114.     while (runlength > 0 && runlength <= 6) {
  115.         int bitsleft = 6;
  116.         int t = 0;
  117.         while (bitsleft) {
  118.         if (runlength <= bitsleft) {
  119.             if (colormode)
  120.             t |= ((1 << runlength)-1) << (bitsleft-runlength);
  121.             bitsleft -= runlength;
  122.             runlength = 0;
  123.             if (bitsleft) {
  124.             if (runs >= erun)
  125.                 break;
  126.             colormode ^= 1;
  127.             runlength = *runs++;
  128.             if (x+runlength > lastx)
  129.                 runlength = runs[-1] = lastx-x;
  130.             x += runlength;
  131.             }
  132.         } else {        /* runlength exceeds bits left */
  133.             if (colormode)
  134.             t |= ((1 << bitsleft)-1);
  135.             runlength -= bitsleft;
  136.             bitsleft = 0;
  137.         }
  138.         }
  139.         if (n == 0) {
  140.         putchar('\n');
  141.         n = maxline;
  142.         }
  143.         putchar(svalue[t]), n--;
  144.     }
  145.     }
  146.     printf(")s\n");
  147. }
  148.  
  149. void
  150. printTIF(TIFF* tif, int pageNumber)
  151. {
  152.     uint32 w, h;
  153.     uint16 unit;
  154.     float xres, yres;
  155.     tstrip_t s, ns;
  156.  
  157.     TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h);
  158.     TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w);
  159.     if (!TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xres)) {
  160.     TIFFWarning(TIFFFileName(tif),
  161.         "No x-resolution, assuming %g dpi", defxres);
  162.     xres = defxres;
  163.     }
  164.     if (!TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yres)) {
  165.     TIFFWarning(TIFFFileName(tif),
  166.         "No y-resolution, assuming %g lpi", defyres);
  167.     yres = defyres;                    /* XXX */
  168.     }
  169.     if (TIFFGetField(tif, TIFFTAG_RESOLUTIONUNIT, &unit) &&
  170.       unit == RESUNIT_CENTIMETER) {
  171.     xres *= 25.4;
  172.     yres *= 25.4;
  173.     }
  174.  
  175.     printf("%%%%Page: \"%d\" %d\n", pageNumber, pageNumber);
  176.     printf("/$pageTop save def gsave\n");
  177.     if (scaleToPage) {
  178.     float yscale = pageHeight / (h/yres);
  179.     float xscale = pageWidth / (w/xres);
  180.     printf("%d %d translate\n",
  181.                (int) (((basePageWidth - pageWidth) * points) * half),
  182.                (int)((yscale*(h/yres)*points) +
  183.                (basePageHeight - pageHeight) * points * half)  );
  184.     printf("%g %g scale\n", (72.*xscale)/xres, -(72.*yscale)/yres);
  185.     } else {
  186.     printf("%d %d translate\n",
  187.                (int) ((basePageWidth - pageWidth) * points * half),
  188.                (int)((72.*h/yres) +
  189.                (basePageHeight - pageHeight) * points * half) );
  190.     printf("%g %g scale\n", 72./xres, -72./yres);
  191.     }
  192.     printf("0 setgray\n");
  193.     TIFFSetField(tif, TIFFTAG_FAXFILLFUNC, printruns);
  194.     ns = TIFFNumberOfStrips(tif);
  195.     row = 0;
  196.     for (s = 0; s < ns; s++)
  197.     (void) TIFFReadEncodedStrip(tif, s, (tdata_t) NULL, (tsize_t) -1);
  198.     printf("p\n");
  199.     printf("grestore $pageTop restore\n");
  200.     totalPages++;
  201. }
  202.  
  203. #define    GetPageNumber(tif) \
  204. TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pn, &ptotal)
  205.  
  206. int
  207. findPage(TIFF* tif, int pageNumber)
  208. {
  209.     uint16 pn = (uint16) -1;
  210.     uint16 ptotal = (uint16) -1;
  211.     if (GetPageNumber(tif)) {
  212.     while (pn != pageNumber && TIFFReadDirectory(tif) && GetPageNumber(tif))
  213.         ;
  214.     return (pn == pageNumber);
  215.     } else
  216.     return (TIFFSetDirectory(tif, pageNumber-1));
  217. }
  218.  
  219. void
  220. fax2ps(TIFF* tif, int npages, int* pages, char* filename)
  221. {
  222.     if (npages > 0) {
  223.     uint16 pn, ptotal;
  224.     int i;
  225.  
  226.     if (!GetPageNumber(tif))
  227.         fprintf(stderr, "%s: No page numbers, counting directories.\n",
  228.         filename);
  229.     for (i = 0; i < npages; i++) {
  230.         if (findPage(tif, pages[i]))
  231.         printTIF(tif, pages[i]);
  232.         else
  233.         fprintf(stderr, "%s: No page number %d\n", filename, pages[i]);
  234.     }
  235.     } else {
  236.     int pageNumber = 1;
  237.     do
  238.         printTIF(tif, pageNumber++);
  239.     while (TIFFReadDirectory(tif));
  240.     }
  241. }
  242.  
  243. #undef GetPageNumber
  244.  
  245. /* 
  246.  * Create a special PostScript font for printing FAX documents.  By taking
  247.  * advantage of the font-cacheing mechanism, a substantial speed-up in 
  248.  * rendering time is realized. 
  249.  */
  250. static void
  251. emitFont(FILE* fd)
  252. {
  253.     static const char* fontPrologue[] = {
  254.     "/newfont 10 dict def newfont begin /FontType 3 def /FontMatrix [1",
  255.     "0 0 1 0 0] def /FontBBox [0 0 512 1] def /Encoding 256 array def",
  256.     "0 1 31{Encoding exch /255 put}for 120 1 255{Encoding exch /255",
  257.     "put}for Encoding 37 /255 put Encoding 40 /255 put Encoding 41 /255",
  258.     "put Encoding 92 /255 put /count 0 def /ls{Encoding exch count 3",
  259.     "string cvs cvn put /count count 1 add def}def 32 1 36{ls}for",
  260.     "38 1 39{ls}for 42 1 91{ls}for 93 1 99{ls}for /count 100",
  261.     "def 100 1 119{ls}for /CharDict 5 dict def CharDict begin /white",
  262.     "{dup 255 eq{pop}{1 dict begin 100 sub neg 512 exch bitshift",
  263.     "/cw exch def cw 0 0 0 cw 1 setcachedevice end}ifelse}def /black",
  264.     "{dup 255 eq{pop}{1 dict begin 110 sub neg 512 exch bitshift",
  265.     "/cw exch def cw 0 0 0 cw 1 setcachedevice 0 0 moveto cw 0 rlineto",
  266.     "0 1 rlineto cw neg 0 rlineto closepath fill end}ifelse}def /numbuild",
  267.     "{dup 255 eq{pop}{6 0 0 0 6 1 setcachedevice 0 1 5{0 moveto",
  268.     "dup 32 and 32 eq{1 0 rlineto 0 1 rlineto -1 0 rlineto closepath",
  269.     "fill newpath}if 1 bitshift}for pop}ifelse}def /.notdef {}",
  270.     "def /255 {}def end /BuildChar{exch begin dup 110 ge{Encoding",
  271.     "exch get 3 string cvs cvi CharDict /black get}{dup 100 ge {Encoding",
  272.     "exch get 3 string cvs cvi CharDict /white get}{Encoding exch get",
  273.     "3 string cvs cvi CharDict /numbuild get}ifelse}ifelse exec end",
  274.     "}def end /Bitfont newfont definefont 1 scalefont setfont",
  275.     NULL
  276.     };
  277.     int i;
  278.     for (i = 0; fontPrologue[i] != NULL; i++)
  279.     fprintf(fd, "%s\n", fontPrologue[i]);
  280. }
  281.  
  282. static int
  283. pcompar(const void* va, const void* vb)
  284. {
  285.     const int* pa = (const int*) va;
  286.     const int* pb = (const int*) vb;
  287.     return (*pa - *pb);
  288. }
  289.  
  290. static    void usage(int code);
  291.  
  292. int
  293. main(int argc, char** argv)
  294. {
  295.     extern int optind;
  296.     extern char* optarg;
  297.     int c, pageNumber;
  298.     int* pages = 0, npages = 0;
  299.     int dowarnings = 0;        /* if 1, enable library warnings */
  300.     time_t t;
  301.     TIFF* tif;
  302.  
  303.     while ((c = getopt(argc, argv, "l:p:x:y:W:H:wS")) != -1)
  304.     switch (c) {
  305.     case 'H':        /* page height */
  306.         pageHeight = atof(optarg);
  307.         break;
  308.     case 'S':        /* scale to page */
  309.         scaleToPage = 1;
  310.         break;
  311.     case 'W':        /* page width */
  312.         pageWidth = atof(optarg);
  313.         break;
  314.     case 'p':        /* print specific page */
  315.         pageNumber = atoi(optarg);
  316.         if (pageNumber < 1) {
  317.         fprintf(stderr, "%s: Invalid page number (must be > 0).\n",
  318.             optarg);
  319.         usage(-1);
  320.         }
  321.         if (pages)
  322.         pages = (int*) realloc((char*) pages, (npages+1)*sizeof (int));
  323.         else
  324.         pages = (int*) malloc(sizeof (int));
  325.         pages[npages++] = pageNumber;
  326.         break;
  327.     case 'w':
  328.         dowarnings = 1;
  329.         break;
  330.     case 'x':
  331.         defxres = atof(optarg);
  332.         break;
  333.     case 'y':
  334.         defyres = atof(optarg);
  335.         break;
  336.     case 'l':
  337.         maxline = atoi(optarg);
  338.         break;
  339.     case '?':
  340.         usage(-1);
  341.     }
  342.     if (npages > 0)
  343.     qsort(pages, npages, sizeof (int), pcompar);
  344.     if (!dowarnings)
  345.     TIFFSetWarningHandler(0);
  346.     printf("%%!PS-Adobe-3.0\n");
  347.     printf("%%%%Creator: fax2ps\n");
  348. #ifdef notdef
  349.     printf("%%%%Title: %s\n", file);
  350. #endif
  351.     t = time(0);
  352.     printf("%%%%CreationDate: %s", ctime(&t));
  353.     printf("%%%%Origin: 0 0\n");
  354.     printf("%%%%BoundingBox: 0 0 %u %u\n",
  355.     (int)(pageHeight*72), (int)(pageWidth*72));    /* XXX */
  356.     printf("%%%%Pages: (atend)\n");
  357.     printf("%%%%EndComments\n");
  358.     printf("%%%%BeginProlog\n");
  359.     emitFont(stdout);
  360.     printf("/d{bind def}def\n"); /* bind and def proc */
  361.     printf("/m{0 exch moveto}d\n");
  362.     printf("/s{show}d\n");
  363.     printf("/p{showpage}d \n");    /* end page */
  364.     printf("%%%%EndProlog\n");
  365.     if (optind < argc) {
  366.     do {
  367.         tif = TIFFOpen(argv[optind], "r");
  368.         if (tif) {
  369.         fax2ps(tif, npages, pages, argv[optind]);
  370.         TIFFClose(tif);
  371.         } else
  372.         fprintf(stderr, "%s: Can not open, or not a TIFF file.\n",
  373.             argv[optind]);
  374.     } while (++optind < argc);
  375.     } else {
  376.     int n;
  377.     FILE* fd;
  378.     char temp[1024], buf[16*1024];
  379.  
  380.     strcpy(temp, "/tmp/fax2psXXXXXX");
  381.     (void) mktemp(temp);
  382.     fd = fopen(temp, "w");
  383.     if (fd == NULL) {
  384.         fprintf(stderr, "Could not create temp file \"%s\"\n", temp);
  385.         exit(-2);
  386.     }
  387.     while ((n = read(fileno(stdin), buf, sizeof (buf))) > 0)
  388.         write(fileno(fd), buf, n);
  389.     tif = TIFFOpen(temp, "r");
  390. #ifndef VMS
  391.     unlink(temp);
  392. #else
  393.     remove(temp);
  394. #endif
  395.     if (tif) {
  396.         fax2ps(tif, npages, pages, "<stdin>");
  397.         TIFFClose(tif);
  398.     } else
  399.         fprintf(stderr, "%s: Can not open, or not a TIFF file.\n", temp);
  400.     fclose(fd);
  401.     }
  402.     printf("%%%%Trailer\n");
  403.     printf("%%%%Pages: %u\n", totalPages);
  404.     printf("%%%%EOF\n");
  405.  
  406.     return (0);
  407. }
  408.  
  409. char* stuff[] = {
  410. "usage: fax2ps [options] [input.tif ...]",
  411. "where options are:",
  412. " -w            suppress warning messages",
  413. " -l chars      set maximum output line length for generated PostScript",
  414. " -p page#      select page to print (can use multiple times)",
  415. " -x xres       set default horizontal resolution of input data (dpi)",
  416. " -y yres       set default vertical resolution of input data (lpi)",
  417. " -S            scale output to page size",
  418. " -W width      set output page width (inches), default is 8.5",
  419. " -H height     set output page height (inchest), default is 11",
  420. NULL
  421. };
  422.  
  423. static void
  424. usage(int code)
  425. {
  426.     char buf[BUFSIZ];
  427.     int i;
  428.  
  429.     setbuf(stderr, buf);
  430.     for (i = 0; stuff[i] != NULL; i++)
  431.         fprintf(stderr, "%s\n", stuff[i]);
  432.     exit(code);
  433. }
  434.